import Api from '../../http/Api';
import { tokenInterceptor } from '../Interceptors';
import { DataResponse, HttpModel, PageInfo, QueryCondition } from './index';
import { AxiosResponse } from 'axios';

export abstract class DataService<T, Id> extends Api {
  public constructor() {
    super();
    this.create();
  }

  protected abstract create(): void;

  protected initTokenInstance = (baseURL: string): Api => {
    return this.initSingle(
      baseURL,
      {
        baseURL,
      },
      tokenInterceptor
    ) as Api;
  };

  selectOneById = (id: Id, useStrict = false): Promise<DataResponse<T>> =>
    this.request<HttpModel<T>>({
      method: this.method.GET,
      url: `/id/${id}`,
      headers: {
        useStrict: String(useStrict),
      },
    });

  selectOne = (record: Partial<T>, useStrict = false): Promise<DataResponse<T>> =>
    this.request({
      method: this.method.POST,
      url: '/search',
      data: record,
      headers: {
        useStrict: String(useStrict),
      },
    });

  selectByIds = (list: Id[], useStrict = false): Promise<DataResponse<T[]>> =>
    this.request({
      method: this.method.POST,
      url: '/list/id',
      data: list,
      // data: list.map(v => BigInt(v)),
      headers: {
        useStrict: String(useStrict),
      },
    });

  select = (condition: QueryCondition<T>): Promise<DataResponse<PageInfo<T>>> =>
    this.request({
      method: this.method.POST,
      url: '/list/search',
      data: condition,
    });

  selectLike = (condition: QueryCondition<T>): Promise<DataResponse<PageInfo<T>>> =>
    this.request({
      method: this.method.POST,
      url: '/list/like',
      data: condition,
    });

  selectAll = (): Promise<DataResponse<PageInfo<T>>> =>
    this.request({
      method: this.method.GET,
      url: '/list',
    });

  selectCount = (record: Partial<T>): Promise<DataResponse<number>> =>
    this.request({
      method: this.method.POST,
      url: '/count',
      data: record,
    });

  insert = (record: Partial<T>): Promise<DataResponse<Id>> =>
    this.request({
      method: this.method.POST,
      data: record,
    });

  insertList = (records: Partial<T>[]): Promise<DataResponse<Id[]>> =>
    this.request({
      method: this.method.POST,
      url: '/list',
      data: records,
    });

  save = (record: Partial<T>): Promise<DataResponse<Id>> =>
    this.request({
      method: this.method.PUT,
      data: record,
    });

  saveList = (records: Partial<T>[]): Promise<DataResponse<Id[]>> =>
    this.request({
      method: this.method.PUT,
      url: '/list',
      data: records,
    });

  update = (record: Partial<T>): Promise<DataResponse<void>> =>
    this.request({
      method: this.method.PATCH,
      data: record,
    });

  updateList = (records: Partial<T>[]): Promise<DataResponse<void>> =>
    this.request({
      method: this.method.PATCH,
      url: '/list',
      data: records,
    });

  deleteById = (id: Id, useStrict = false): Promise<AxiosResponse<void>> =>
    this.request({
      method: this.method.DELETE,
      url: `/id/${id}`,
      headers: {
        useStrict: String(useStrict),
      },
    });

  deleteByIds = (list: Id[], useStrict = false): Promise<AxiosResponse<void>> =>
    this.request({
      method: this.method.DELETE,
      url: '/list/id',
      data: list,
      // data: list.map(v => BigInt(v)),
      headers: {
        useStrict: String(useStrict),
      },
    });
}

export abstract class AssociationService<T, M, N, Id, Mid, Nid> extends DataService<T, Id> {
  selectOneByForeignIds = (mid: Mid, nid: Nid): Promise<DataResponse<T>> =>
    this.request({
      method: this.method.POST,
      url: '/search',
      data: this.model(mid, nid),
    });

  selectNListByMId = (id: Mid): Promise<DataResponse<N[]>> =>
    this.request({
      method: this.method.GET,
      url: `/mid/${id}`,
    });

  selectNListByMList = (ids: Mid[]): Promise<DataResponse<N[]>> =>
    this.request({
      method: this.method.POST,
      url: '/list/mid',
      data: ids,
    });

  selectMListByNId = (id: Nid): Promise<DataResponse<M[]>> =>
    this.request({
      method: this.method.GET,
      url: `/nid/${id}`,
    });

  selectMListByNList = (ids: Nid[]): Promise<DataResponse<M[]>> =>
    this.request({
      method: this.method.POST,
      url: '/list/nid',
      data: ids,
    });

  public abstract getMid(model: T): Mid;

  public abstract getNid(model: T): Nid;

  public abstract model(mid?: Mid, nid?: Nid): Partial<T>;
}
